package cn.com.dcsgo.service.impl;

import cn.com.dcsgo.dao.StudentDao;
import cn.com.dcsgo.pojo.Student;
import cn.com.dcsgo.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * StudentServiceImpl
 *
 * @author Dcsgo
 * @since 2025/2/4 16:05
 */
@Service
public class StudentServiceImpl implements StudentService {
    @Autowired
    private StudentDao studentDao;

    @Override
    @Transactional(readOnly = true)
    public List<Student> findAll() {
        return studentDao.queryAll();
    }

    /**
     * 通过使用@Transactional我们可以指定特定类及其方法开启事务
     * 该注解使用到类上表示对当前类的所有方法开启事务，使用在方法上表示当前方法开启事务
     * 默认通过抛出异常来触发事务回滚(实现原理类似AOP)
     * rollbackFor属性可以指定特定异常触发事务回滚
     * noRollbackFor属性可以指定特定异常不触发事务回滚
     * 如果省略rollbackForSpring 只会在遇到运行时异常
     * (unchecked exceptions，通常是继承自 RuntimeException 的异常)
     * 时回滚事务，而对于已检查异常(checked exceptions,例如 IOException 或 SQLException)则不会自动回滚
     * 因此建议指定rollbackFor为Throwable，避免因为没有考虑到某些异常的情况而导致事务没有回滚
     * readOnly属性表示开启事务的方法只能是查询(否则会报错),spring将会对其进行事务的优化
     * 有啥用呢？查询也不需要开事务啊？当类已经声明开启事务时，当前类下的纯查询业务的方法可以通过再次使用@Transactional
     * 声明，并指定readOnly让spring对其进行优化(方法上的@Transactional会覆盖类上的@Transactional注解配置的功能)
     * timeout属性可以指定超时时间(单位秒)
     * 当注解的方法运行时间超过这个规定时间后会回滚事务并抛出相应的超时异常(TransactionTimedOutException)
     * isolation属性可以指定事务的隔离级别
     * Isolation.READ_UNCOMMITTED(1),
     * READ_COMMITTED(2),
     * REPEATABLE_READ(4),
     * SERIALIZABLE(8)
     */
    @Override
    @Transactional(rollbackFor = Throwable.class, timeout = 3, isolation = Isolation.READ_COMMITTED)
    public void changeInfo() {
        studentDao.updateAgeById(7, 1);
        System.out.println("____________");
        int a = 1 / 0;
        studentDao.updateNameById("test", 1);
    }

    /**
     * 事务传播性：当一个类调用另一个类中的方法，并涉及多个事务时(两个类均使用了声明式事务)
     * 那么可以通过@Transactional注解的propagation属性来配置多个事务间的处理方式
     * 该配置使用在被调用类或方法上
     * Propagation.REQUIRED(默认)，存在事务则加入，否则创建一个新事务(推荐使用)
     * Propagation.REQUIRES_NEW，总是创建新事务，多个事务是独立的，被调用方法抛异常不会触发调用方法的事务回滚
     * Propagation.SUPPORTS ,如果当前存在事务，则加入事务，否则以非事务方式执行
     * Propagation.MANDATORY ,必须在一个已有的事务中执行，否则抛出异常
     * Propagation.NOT_SUPPORTED ,以非事务方式执行，如果当前存在事务，挂起该事务
     * Propagation.NEVER ,必须在没有事务的情况下执行，否则抛出异常
     * Propagation.NESTED ,如果当前存在事务，则在该事务中嵌套一个新事务，如果没有事务，则创建一个新事务
     */
    @Override
    @Transactional(rollbackFor = Throwable.class,propagation = Propagation.REQUIRED)
    public void changeAge() {
        studentDao.updateAgeById(50, 1);
    }

    @Override
    @Transactional(rollbackFor = Throwable.class,propagation = Propagation.REQUIRES_NEW)
    public void changeName() {
        studentDao.updateNameById("hao", 1);
        int a = 1 / 0;
    }


}
